package com.twq.types.typeparam.variance

/**
 * Created by tangweiqun on 2017/12/6.
 */
class Queue[+T](elems: List[T]) {

  def head: T = elems.head

  def tail: Queue[T] = new Queue(elems.tail)

  override def toString: String = elems.mkString
}

object Queue {
  def main(args: Array[String]): Unit = {
    //1、当类型参数和子类结合的时候，我们看看会出现什么情况

    //1.1 比如，String是AnyRef的子类，那么Queue[String]是Queue[AnyRef]的子类吗？
    val q1 = new Queue[String](List("this", "is", "a", "example"))

    def foo(q: Queue[AnyRef]) = {}

    foo(new Queue[AnyRef](List()))
    foo(q1)

    //如果Queue[String]是Queue[AnyRef]的子类，那么下面的代码应该可以编译过
    //但是Scala类型参数的默认的行为是不变(nonvariant)
    //我们需要在Queue的类型参数前面加上 + 号，使得Queue[String]是Queue[AnyRef]的子类
    //我们称之为Queue的类型参数T是可以协变的(covariant)，因为Queue只有一个类型参数，所以我们就可以直接说Queue是可以协变的
    //foo(q1)

    //协变(co-variant)：如果类型S是类型T的子类，那么Queue[S]是Queue[T]的子类
    val queueAny: Queue[AnyRef] = q1

    //1.2 如果类型S是类型T的子类，那么Queue[T]是Queue[S]的子类，这种情况，我们称之为逆变(contra-variant)
    //需要在类型参数前面加上 - 才能使得一个类型支持逆变

    //1.3 类型参数的型变：协变(co-variant)、逆变(contra-variant)以及不变(non-variant)
    //类型参数前面的 + 和 - 符号，我们称之为variance annotations(型变注释)
  }


}
